package com.spzx.product.controller;

import com.alibaba.fastjson2.JSON;
import com.github.pagehelper.PageHelper;
import com.spzx.common.core.exception.ServiceException;
import com.spzx.common.core.web.controller.BaseController;
import com.spzx.common.core.web.domain.AjaxResult;
import com.spzx.common.core.web.page.TableDataInfo;
import com.spzx.product.api.domain.ProductSkuVo;
import com.spzx.product.domain.Brand;
import com.spzx.product.domain.Product;
import com.spzx.product.domain.ProductSku;
import com.spzx.product.query.SkuQuery;
import com.spzx.product.service.*;
import com.spzx.product.vo.*;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;

@Tag(name = "聚合数据")
@RestController
@RequestMapping("/channel")
public class ChannelController extends BaseController {


    @Autowired
    private ICategoryService categoryService;

    @Autowired
    private IProductSkuService productSkuService;

    @Autowired
    private IBrandService brandService;

    @Autowired
    private ISkuStockService skuStockService;

    @Autowired
    private IProductService productService;

    @Autowired
    private IProductDetailsService productDetailsService;

    @Autowired
    private RedisTemplate redisTemplate;


    @Operation(summary = "首页展示数据，一级分类以及畅销商品TOP20")
    @GetMapping("/index")
    public AjaxResult index() {
        IndexDataVo indexDataVo = new IndexDataVo();
        //1.封装VO中一级分类列表
        indexDataVo.setCategoryList(categoryService.selectTopCategoryList());
        //2.封装VO畅销商品TOP20列表
        indexDataVo.setProductSkuList(productSkuService.selectHotProductSkuList());
        return success(indexDataVo);
    }


    @Operation(summary = "查询所有分类，将子分类封装到children属性中")
    @GetMapping("/category")
    public AjaxResult categoryList() {
        List<CategoryVo> list = categoryService.selectAllCategoryList();
        return success(list);
    }

    @GetMapping("/brand")
    @Operation(summary = "查询所有品牌列表")
    public AjaxResult brandList() {
        List<Brand> list = brandService.list();
        return success(list);
    }


    @Operation(summary = "多条件分页查询商品列表")
    @GetMapping("/skuList/{pageNum}/{pageSize}")
    public TableDataInfo skuList(@PathVariable int pageNum, @PathVariable int pageSize, SkuQuery skuQuery) {
        //由于这个接口特殊分页参数采用路径传参 故父类中startPage方法无法从请求参数中获取，采用手动封装分页参数
        PageHelper.startPage(pageNum, pageSize);
        //调用业务逻辑查询商品列表
        List<ProductSkuVo> list = productSkuService.selectProductSkuList(skuQuery);
        return getDataTable(list);
    }

    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;

    /**
     * 商品详情
     *
     * @param skuId
     * @return
     */
    @Operation(summary = "根据skuId查询商品详情渲染门户商品详情页面")
    @GetMapping("/item/{skuId}")
    public AjaxResult item(@PathVariable Long skuId) {

        //TODO 判断机制：查询缓存以及数据库前能判断用户访问商品ID是否存在，不存在抛出异常  场景：大量数据判断元素存在或不存在
        //0. 执行业务逻辑前，查询Redis中bitmap判断商品ID是否存在，如果不存在抛出异常
        String key = "product:sku:data";
        Boolean exists = redisTemplate.opsForValue().getBit(key, skuId);
        if (!exists) {
            throw new ServiceException("商品不存在！");
        }

        ItemVo itemVo = new ItemVo();
        //1.根据skuId查询商品sku信息 创建有返回值异步任务
        CompletableFuture<ProductSku> productSkuCompletableFuture = CompletableFuture.supplyAsync(() -> {
            ProductSku sku = productSkuService.findSkuById(skuId);
            itemVo.setProductSku(sku);
            return sku;
        }, threadPoolExecutor);

        //2.根据SKUID查询当前SKU价格信息
        CompletableFuture<Void> priceCompletableFuture = CompletableFuture.runAsync(() -> {
            SkuPriceVo skuPriceVo = productSkuService.getSkuPrice(skuId);
            itemVo.setSkuPrice(skuPriceVo);
        }, threadPoolExecutor);

        //3.根据SKUID查询当前SKU库存信息
        CompletableFuture<Void> stockCompletableFuture = CompletableFuture.runAsync(() -> {
            SkuStockVo skuStockVo = skuStockService.getSkuStock(skuId);
            itemVo.setSkuStock(skuStockVo);
        }, threadPoolExecutor);

        //4.根据商品（Spu）ID查询轮播图 在product表
        CompletableFuture<Void> urlAndSpecCompletableFuture = productSkuCompletableFuture.thenAcceptAsync(sku -> {
            Product product = productService.getById(sku.getProductId());
            String sliderUrls = product.getSliderUrls();
            if (!ObjectUtils.isEmpty(sliderUrls)) {
                //1.png,2.png
                itemVo.setSliderUrlList(sliderUrls.split(","));
            }
            //5.根据商品（Spu）ID查询商品规格信息 在product表 将字符串转为"[{}]"，数组对象
            String specValue = product.getSpecValue();
            itemVo.setSpecValueList(JSON.parseArray(specValue));
        }, threadPoolExecutor);

        //6.根据商品（Spu）ID查询所有 SKU跟规格 映射关系  形式："规格值":SKUID
        CompletableFuture<Void> specSkuIdMapCompletableFuture = productSkuCompletableFuture.thenAcceptAsync(sku -> {
            Map<String, Long> skuSpecValueMap = productSkuService.getSkuSpecValueMap(sku.getProductId());
            itemVo.setSkuSpecValueMap(skuSpecValueMap);
        }, threadPoolExecutor);

        //7.根据商品（Spu）ID查询商品详情图片 在product_details表
        CompletableFuture<Void> detailsCompletableFuture = productSkuCompletableFuture.thenAcceptAsync(sku -> {
            String[] detailsImageUrlList = productDetailsService.getDetailsImageUrlList(sku.getProductId());
            itemVo.setDetailsImageUrlList(detailsImageUrlList);
        }, threadPoolExecutor);


        //8.组合异步任务
        CompletableFuture.allOf(
                productSkuCompletableFuture,
                priceCompletableFuture,
                stockCompletableFuture,
                urlAndSpecCompletableFuture,
                specSkuIdMapCompletableFuture,
                detailsCompletableFuture
        ).join();

        return success(itemVo);
    }


}
